package com.example.utils.util;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * TODO  16进制字符串的异或运算
 *       传入例子:   Key:	8BAF473F2F8FD09487CCCBD7097C6862
 *                  RAND: 	B78C030000000000B78C030000000000
 *       方法是针对两个固定值16进制，16字节长的字符串之间的异或运算，
 *       先进行拆分： Key: 8B  AF  47  3F  2F  8F  D0  94  87  CC  CB  D7  09  7C  68  62
 *                       |    |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
 *                 RAND: B7  8C  03  00  00  00  00  00  B7  8C  03  00  00  00  00  00
 *                       |    |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
 *     运算之后的值: XRES: 3C  23  44  F2  F8  FD  09  43  04  0C  8D  70  90  7C  68  62
 *
 * @ClassName XOR
 * @Author xiaojiang
 * @Date 2022/2/9 下午 12:09
 */
public class XOR {

    public static void main(String[] args) throws Exception {
        String Key = "8BAF473F2F8FD09487CCCBD7097C6862";
        System.out.println("Key   = " + Key);
        String RAND= "B78C030000000000B78C030000000000";
        System.out.println("RAND  = " + RAND);
        //String XRES = "3C23443F2F8FD0943040C8D7097C6862";
        String SQN = "000000000022";
        String SQN_MS = "000000000033";
        String AMF = "8080";

        String IMPI = "460001234567890@ims.mnc000.mcc460.3gppnetwork.org";
        String NAF_Id = "naf.mnc00.mcc460.pub.3gppnetwork.org";

        // 鉴权五元组 获取
        String XRES = checkcode(Key, RAND);
        System.out.println("XRES  = " + XRES);
        String CK  = moveToLeft(XRES, 2);
        System.out.println("CK    = " + CK );
        String IK   = moveToLeft(XRES, 4);
        System.out.println("IK    = " + IK );
        String AK    = moveToLeft(XRES, 6).substring(0,12);
        System.out.println("AK    = " + AK  );
        String MAC_A = checkcode(XRES.substring(0, 16), SQN + AMF);
        System.out.println("MAC_A = " + MAC_A  );
        String MAC_S = MAC_A;
        System.out.println("MAC_S = " + MAC_S  );
        String AUTN = checkcode(SQN, AK) + AMF + MAC_A;
        System.out.println("AUTN  = " + AUTN);
        String AUTS = checkcode(SQN_MS, AK) + AMF + MAC_S;
        System.out.println("AUTS  = " + AUTS);
        String SQN_MS1 = checkcode(AUTS.substring(0, 12), AK);
        System.out.println("SQN_MS= " + SQN_MS1);

        // Nonce计算
        String str = RAND + "," + AUTN + "," + "";
        String Nonce = ByteUtil.encodeBase64(str.getBytes(StandardCharsets.UTF_8));
        System.out.println("Nonce = " + Nonce);

        // 密钥Ks
        String Ks = CK + IK;
        System.out.println("Ks    = " + Ks);

        // KDF 算法 参数准备
        String FC = "0x01";
        //-----  gba-me
        String test = "gba-me";
        int length = test.length();
        System.out.println("length = " + length);
        byte[] bytes = unsignedShortToByte2(length);
        String gba_me_length = Hex.encodeHexStr(bytes);
        System.out.println("gba_me_length = " + gba_me_length);
        String gba_me_Ks = strTo16(test) + gba_me_length;
        System.out.println("gba_me_Ks = " + gba_me_Ks);
        //----   RAND
        String RAND_length = Hex.encodeHexStr(unsignedShortToByte2(RAND.length()/2));
        System.out.println("RAND_length = " + RAND_length);
        String RAND_Ks = RAND + RAND_length;
        System.out.println("RAND_Ks = " + RAND_Ks);
        //----   IMPI
        String IMPI_length = Hex.encodeHexStr(unsignedShortToByte2(IMPI.length()));
        System.out.println("IMPI_length = " + IMPI_length);
        String IMPI_Ks = strTo16(IMPI) + IMPI_length;
        System.out.println("IMPI_Ks = " + IMPI_Ks);
        //----   NAF_Id
        String NAF_Id_length = Hex.encodeHexStr(unsignedShortToByte2(NAF_Id.length()));
        System.out.println("NAF_Id_length = " + NAF_Id_length);
        String NAF_Id_Ks = strTo16(NAF_Id) + NAF_Id_length;
        System.out.println("NAF_Id_Ks = " + NAF_Id_Ks);


        // Ks_NAF 计算
        String data = FC + gba_me_Ks + RAND_Ks + IMPI_Ks + NAF_Id_Ks;
        System.out.println("data = " + data);
        String Ks_NAF = HMACSHA256(data, "0x" + Ks);
        System.out.println("Ks_NAF = " + Ks_NAF);

//==================================================
        /*String Key = "8BAF473F2F8FD09487CCCBD7097C6862";
        System.out.println("Key   = " + Key);
        String RAND= "B78C030000000000B78C030000000000";
        System.out.println("RAND  = " + RAND);
        //             3C 23 443F2F8FD0943040C8D7097C6862
        String XRES = "3C23443F2F8FD0943040C8D7097C6862";
        String checkcode = checkcode(Key, RAND);
        System.out.println("checkcode = " + checkcode);
        System.out.println(XRES.equals(checkcode));*/

//==================================================
        /*String AUTS6  = "3F2F8FD09403";
        String AK     = "3F2F8FD09430";
        String SQN_MS = "000000000033";

        String checkcode = checkcode(SQN_MS, AK);

        String xor = checkcode(AUTS6, AK);
        System.out.println("AUTS6 = " + checkcode);
        System.out.println("SQN_MS = " + xor);
        String xor1 = xor("30", "33");
        System.out.println("xor1 = " + xor1);*/
    }

    /**
     *  TODO   传入已经拆分的16进制 比如 8B 和B7
     *
     * @Param : strHex_X
     * @Param : strHex_Y
     * @return String
     * @Author 江
     * @Date 2022/2/9 下午 12:11
     */
    private static String xor(String strHex_X,String strHex_Y){
        //将x、y转成二进制形式
        String anotherBinary=Integer.toBinaryString(Integer.valueOf(strHex_X,16));
        String thisBinary=Integer.toBinaryString(Integer.valueOf(strHex_Y,16));
        String result = "";
        //判断是否为8位二进制，否则左补零
        if(anotherBinary.length() != 8){
            for (int i = anotherBinary.length(); i <8; i++) {
                anotherBinary = "0"+anotherBinary;
            }
        }
        if(thisBinary.length() != 8){
            for (int i = thisBinary.length(); i <8; i++) {
                thisBinary = "0"+thisBinary;
            }
        }
        //异或运算
        for(int i=0;i<anotherBinary.length();i++){
            //如果相同位置数相同，则补0，否则补1
            if(thisBinary.charAt(i)==anotherBinary.charAt(i))
                result+="0";
            else{
                result+="1";
            }
        }
        // 转为 16 进制返回
        return Integer.toHexString(Integer.parseInt(result, 2));
    }

    /**
     *  TODO  将传入的16进制分解进行异或运算
     * @Param : aara
     * @Param : bara
     * @return Please change caller according to com.intellij.openapi.project.IndexNotReadyException documentation
     * @Author 江
     * @Date 2022/2/9 下午 12:09
     */
    public static String checkcode(String aara,String bara){
        // 两两分解 为 数组
        String[] dateArr = new String[16];
        for (int i = 0; i < 16; i++) {
            dateArr[i] = aara.substring(i * 2, i * 2 + 2);
        }
        // 两两分解 为 数组
        String[] dateBrr = new String[16];
        for (int i = 0; i < 16; i++) {
            dateBrr[i] = bara.substring(i * 2, i * 2 + 2);
        }

        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < dateArr.length; i++) {
            String code = xor(dateArr[i], dateBrr[i]);
            // 如果返回只有一个长度， 则进行补位0
            if (code.length()<2){
                code = "0" + code;
            }
            stringBuffer.append(code);
        }
        return stringBuffer.toString();
    }

    //返回左移n位字符串方法
    private static String moveToLeft(String str,int position) {
        String str1=str.substring(position);
        String str2=str.substring(0, position);
        return str1+str2;
    }
    //返回右移n位字符串方法
    private static String moveToRight(String str,int position) {
        String str1=str.substring(str.length()-position);
        String str2=str.substring(0, str.length()-position);
        return str1+str2;
    }

    /**
     * 字符串转化成为16进制字符串  gba-me  -->  6762612d6d65
     * @param s
     * @return
     */
    public static String strTo16(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = (int) s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }

    /**
     * 16进制转换成为string类型字符串  6762612d6d65  -->  gba-me
     * @param s
     * @return
     */
    public static String hexStringToString(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace(" ", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, "UTF-8");
            new String();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }

    /**
     *  TODO  生成HMACSHA256的方法
     * @Param : data  要加密的数据
     * @Param : key  密钥
     * @return String 加密后的数据
     * @Author 江
     * @Date 2022/2/9 下午 17:37
     */
    public static String HMACSHA256(String data, String key) throws Exception {

        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");

        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");

        sha256_HMAC.init(secret_key);

        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));

        StringBuilder sb = new StringBuilder();

        for (byte item : array) {

            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));

        }

        return sb.toString().toUpperCase();

    }

    /**
     *  TODO   int 转为 byte[]
     * @Author 江
     */
    public static byte[] unsignedShortToByte2(int s) {
        byte[] targets = new byte[2];
        targets[0] = (byte) (s >> 8 & 0xFF);
        targets[1] = (byte) (s & 0xFF);
        return targets;
    }

}
